package org.mashart.pink.m.gui;

import java.util.Vector;
//import javax.microedition.lcdui.Command;
//import javax.microedition.lcdui.CommandListener;
//import javax.microedition.lcdui.Display;
//import javax.microedition.lcdui.Displayable;
//import javax.microedition.lcdui.Form;
//import javax.microedition.lcdui.StringItem;
//import javax.microedition.lcdui.TextField;
//import javax.microedition.lcdui.ChoiceGroup;
//import javax.microedition.lcdui.List;
//import javax.microedition.lcdui.Alert;
//import javax.microedition.lcdui.AlertType;
import javax.microedition.midlet.MIDletStateChangeException;

import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.layouts.*;

import org.mashart.pink.m.PinkrMIDlet;
import org.mashart.pink.m.store.Preferences;
import org.mashart.pink.m.store.FileManager;

/**
 * GUI for configuring the preferences.
 */
public class PreferencesGUI implements ActionListener {

    /**
     * Parent of the Gui: the very MIDlet class instance.
     */
    private PinkrMIDlet midlet;

    /**
     * We keep reference to the mobile device display so not to call
     * <code>Display.getDisplay(midlet)</code> every time we need it.
     *
     * Used to display the current <code>Canvas</code> or <code>Form</code>
     * to the user.
     */
//    private Display display;

    /**
     * Preferences persistences storage
     */
    Preferences pref;

    // edit user information
    private Form fUser;
    // select HTTP connection / File saving
    private Form fWsConnector;
    // select sending interval
    private Form fSendInterval;
    // select user profile
    private Form fProfile;
    // select device type
    private Form fDeviceTypes;
    // select BT device
    private Form fBtDevices;
    // user id
    private TextField tUser;
    // path on phone file system, for saving data file
    private TextField tPath;
    // host URL
    private TextField tUrl;
    // interactive response information after the user enter sth. in "user info" form
    private Label sInfoEditUser;
    // interactive response information after the user enter sth. in "HTTP connection" form
    private Label sInfoConnection;
    // interactive response information for "Device Types" form, when scanning for bt devices
    private Label sInfoScanning;

    // select HTTP connection / File saving
    private ButtonGroup lsWsConnector;
    // select sending interval
    private ButtonGroup lsSendInterval;
    // select user profile
    private ButtonGroup lsProfile;
    // option of auto pause
    private ButtonGroup lsOptions;
    private CheckBox cbAutoPause;
    private List lsDeviceTypes;
    private List lsBtDevices;
//    private DefaultListModel lmDeviceTypes;
//    private DefaultListModel lmBtDevices;
//    private ButtonGroup bgDeviceTypes;
//    private ButtonGroup bgBtDevices;

    private final Command START_ROUND_CMD = new Command("Start");
    private final Command NEXT_CMD = new Command("Next");
    private final Command FINISH_CMD = new Command("Finish");
    private final Command EXIT_CMD = new Command("Exit");
    private final Command BT_DISCOVER_CMD = new Command("Refresh");
    private final Command SELECT_CMD = new Command("Select");
    private final Command CONFIG_CMD = new Command("Config");

    private final String DeviceTypesMenuTitle = new String("Choose a device type");
    private final String DevicesMenuTitle = new String("Choose a device");
    private final String InternalDeviceMenuItem = new String("Built-in GPS");
    private final String BtDeviceMenuItem = new String("Bluetooth GPS");

    /**
     * Constructor
     */
    public PreferencesGUI(){
        pref = Preferences.getInstance();
    }

    /**
     * Set the midlet
     */
    public void setMidlet(PinkrMIDlet m){
        this.midlet = m;
        Display.init(m);
//        this.display = Display.getDisplay(midlet);
    }

    /**
     * Entrance of preferences editor
     * @param forced if false, do not edit the preference if already set, if true, edit the preference regardless whether already set.
     */
    public void showPreferencesEditor(boolean forced){
        // if forced to edit the preferences, or the "user" is not set yet
        if( forced || pref.get(Preferences.kConfigured) == null){
            editUser();
        }else{
            String type = pref.get(Preferences.kDeviceType);
            String url = pref.get(Preferences.kBtConnectionURL);
            if ( type != null && url != null ) {
                this.midlet.setDevice(type, url);
            } else {
                editUser();
            }
        }
    }

    /**
     * Edit the user id and password
     */
    public void editUser(){
        String path = pref.get(Preferences.kPath);
        if(path == null){
            path = FileManager.getPreferedPath();
        }
        String strUser = pref.get(Preferences.kUser);
        if ( strUser == null ) {
            strUser = "";
        }
        tUser = new TextField( strUser, 32 );
        // current pink id is only numeric, set this constraint for input convenience
        tUser.setConstraint(TextField.NUMERIC);
        tPath = new TextField(path, 32);
        tPath.setEditable(false);
        sInfoEditUser = new Label();

        fUser = new Form("User Info");
        fUser.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        fUser.addComponent(new Label("User ID:"));
        fUser.addComponent(tUser);
        fUser.addComponent(new Label("Data Directory:"));
        fUser.addComponent(tPath);
        fUser.addComponent(sInfoEditUser);

        fUser.addCommand(NEXT_CMD);
        fUser.addCommand(FINISH_CMD);
        fUser.addCommandListener(this);
        fUser.show();
    }

    /**
     * Edit the WsConnector
     */
    public void editWsConnector(){
        int selectedIndex = 0;
        String strSlectedIndex = pref.get(Preferences.kWsConnector);
        if(strSlectedIndex != null){
            if(strSlectedIndex.equals(Preferences.vHTTP)){
                selectedIndex = 0;
            }
            else if(strSlectedIndex.equals(Preferences.vFile)){
                selectedIndex = 1;
            }
        }

        Label radioButtonsLabel = new Label("Data Output");
        lsWsConnector = new ButtonGroup();
        RadioButton rbHttp = new RadioButton(Preferences.vHTTP);
        RadioButton rbFile = new RadioButton(Preferences.vFile);
        lsWsConnector.add(rbHttp);
        lsWsConnector.add(rbFile);
        lsWsConnector.setSelected(selectedIndex);

        fWsConnector = new Form();
        fWsConnector.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        fWsConnector.addComponent(radioButtonsLabel);
        fWsConnector.addComponent(rbHttp);
        fWsConnector.addComponent(rbFile);

        fWsConnector.addCommand(NEXT_CMD);
        fWsConnector.addCommand(FINISH_CMD);
        fWsConnector.addCommandListener(this);
        fWsConnector.show();
    }

    /**
     * Edit the sending interval
     */
    public void editSendInterval(){
        String url = pref.get(Preferences.kUrl);
        if ( url == null || url.length() == 0 ) {
            url = "http://pink.mashart.org";
        }
        tUrl = new TextField(url, 32);

        int [] intervals = {1,5,10,30,60};
        int selectedIndex = 1;
        String strSendInterval = pref.get(Preferences.kSendInterval);
        if(strSendInterval != null){
            for ( int i = 0 ; i < intervals.length ; i++ ) {
                if ( Integer.parseInt(strSendInterval) == intervals[i] ) {
                    selectedIndex = i;
                    break;
                }
            }
        }

        Label radioButtonsLabel = new Label("Interval for sending data (sec)");
        lsSendInterval = new ButtonGroup();
        RadioButton [] rbs = new RadioButton[ intervals.length ];
        for ( int i = 0 ; i < intervals.length ; i++ ) {
            rbs[ i ] = new RadioButton(String.valueOf(intervals[i]));
            lsSendInterval.add(rbs[ i ]);
        }
//        for ( int i = 5 ; i >= 1 ; i-- ) {
//            lsSendInterval.append(String.valueOf(i), null);
//        }
        lsSendInterval.setSelected(selectedIndex);

        sInfoConnection = new Label();

        fSendInterval = new Form("HTTP Connection");
        fSendInterval.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        fSendInterval.addComponent(new Label("Server URL:"));
        fSendInterval.addComponent(tUrl);
        fSendInterval.addComponent(radioButtonsLabel);
        for ( int i = 0 ; i < intervals.length ; i++ ) {
            fSendInterval.addComponent(rbs[ i ]);
        }
        fSendInterval.addComponent(sInfoConnection);
        fSendInterval.addCommand(NEXT_CMD);
        fSendInterval.addCommand(FINISH_CMD);
        fSendInterval.addCommandListener(this);
        fSendInterval.show();
    }

    /**
     * Edit the user profile and auto pause option
     */
    public void editProfile(){
        String vAutoPause = pref.get(Preferences.kAutoPause);
        boolean autoPauseSelected;
        if ( vAutoPause != null ) {
            autoPauseSelected = vAutoPause.equals(Preferences.vYes);
        }else{
            // default: not selected
            autoPauseSelected = false;
        }

        Label checkBoxesLabel = new Label("Options");
        cbAutoPause = new CheckBox("Auto-pause Mode");
        cbAutoPause.setSelected(autoPauseSelected);

        int selectedIndex;
        String strSlectedIndex = pref.get(Preferences.kProfile);
        if(strSlectedIndex != null){
            selectedIndex = Integer.parseInt(strSlectedIndex);
        }else{
            // default: biker
            selectedIndex = 2;
        }

        Label radioButtonsLabel = new Label("You are a ...");
        lsProfile = new ButtonGroup();
        RadioButton rbs[] = new RadioButton[Preferences.vProfile.length];
        for ( int i = 0 ; i < Preferences.vProfile.length ; i++ ) {
            rbs[ i ] = new RadioButton(Preferences.vProfile[i]);
            lsProfile.add(rbs[i]);
        }

        lsProfile.setSelected(selectedIndex);

        fProfile = new Form();
        fProfile.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        fProfile.addComponent(checkBoxesLabel);
        fProfile.addComponent(cbAutoPause);
        fProfile.addComponent(radioButtonsLabel);
        for ( int i = 0 ; i < Preferences.vProfile.length ; i++ ) {
            fProfile.addComponent(rbs[i]);
        }

        fProfile.addCommand(NEXT_CMD);
        fProfile.addCommand(FINISH_CMD);
        fProfile.addCommandListener(this);
        fProfile.show();
    }

    /**
     * Shows available GPS devices
     */
    public void showDeviceTypesConsole(boolean internalGpsFound, boolean btLocalDeviceFound){
        lsDeviceTypes = new List();
        sInfoScanning = new Label();

        fDeviceTypes = new Form(DeviceTypesMenuTitle);
        fDeviceTypes.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        if(internalGpsFound){
            lsDeviceTypes.addItem(InternalDeviceMenuItem);
        }
        if(btLocalDeviceFound){
            lsDeviceTypes.addItem(BtDeviceMenuItem);
        }
        if(internalGpsFound || btLocalDeviceFound){
            lsDeviceTypes.setSelectedIndex(0);
            fDeviceTypes.addComponent(lsDeviceTypes);
            fDeviceTypes.addComponent(sInfoScanning);
            fDeviceTypes.addCommand(SELECT_CMD);
            fDeviceTypes.addCommandListener(this);
            fDeviceTypes.show();
        } else{
            Form noGpsForm = new Form("No GPS device found!");
            noGpsForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
//                    noGpsForm.addCommand(DISCOVER_CMD);
            noGpsForm.addCommand(EXIT_CMD);
            noGpsForm.addCommandListener(this);
            noGpsForm.show();
        }
    }

    /**
     * Shows available bluetooth remote devices
     */
    public void showBtDevicesConsole(Vector names){
        if(names != null && names.size() > 0){
            lsBtDevices = new List(names);
            lsBtDevices.setSelectedIndex(0);
            fBtDevices = new Form(DevicesMenuTitle);
            fBtDevices.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
            fBtDevices.addComponent(lsBtDevices);
            fBtDevices.addCommand(SELECT_CMD);
            fBtDevices.addCommand(BT_DISCOVER_CMD);
            fBtDevices.addCommandListener(this);
            fBtDevices.show();
        }else{
            Form noGpsForm = new Form("No bluetooth GPS device found!");
            noGpsForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
            noGpsForm.addCommand(BT_DISCOVER_CMD);
            noGpsForm.addCommand(EXIT_CMD);
            noGpsForm.addCommandListener(this);
            noGpsForm.show();
        }
        Display.getInstance().flashBacklight(3000);
    }

    /**
     * Show initialization error
     */
    public void showInitializationError(){
        Form f = new Form("Unable to initialize!");
        f.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        f.addComponent( new Label("The previous configured GPS device maybe unavailable. You can try to reconfigure.") );
        f.addCommand(CONFIG_CMD);
        f.addCommand(EXIT_CMD);
        f.addCommandListener(this);
        f.show();
    }

    /**
     * Called after all initialization is done.
     * Shows <code>debug StringItem</code> on the display
     */
    public void showReadyConsole() {
        Form readyForm = new Form("Pinkr ready");
        readyForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS) );
        Label mUserItem = new Label("User ID: " + pref.get(Preferences.kUser));

        String strProfileIndex = pref.get(Preferences.kProfile);
        Label mProfile = new Label("You are a " + Preferences.vProfile[Integer.parseInt(strProfileIndex)]);

        Label mAutoPause = new Label("Auto-Pause Mode Enabled: " + pref.get(Preferences.kAutoPause));
        Label mDeviceItem = new Label("GPS Device: " + pref.get(Preferences.kDeviceType));

        String wsconn = pref.get(Preferences.kWsConnector);
        Label mWsConnectorItem = new Label("Data Output: " + wsconn);
        
        readyForm.addComponent(mUserItem);
        readyForm.addComponent(mProfile);
        readyForm.addComponent(mAutoPause);
        readyForm.addComponent(mDeviceItem);
        readyForm.addComponent(mWsConnectorItem);
        if ( wsconn.equals(Preferences.vHTTP) ) {
            Label mSendIntervalItem = new Label("Send data every " + pref.get(Preferences.kSendInterval) + " second");
            readyForm.addComponent(mSendIntervalItem);
        }
        readyForm.addComponent( new Label("You can press the start button to start a round.") );
        readyForm.addCommand(START_ROUND_CMD);
        readyForm.addCommand(CONFIG_CMD);
        readyForm.addCommandListener(this);
        readyForm.show();
    }

    /**
     * Shows a message on screen. Used as waiting screen.
     * @param title
     * @param contents
     */
    public void showAlert( String msg ){
        Dialog.show("Alert", msg, Dialog.TYPE_WARNING, null, "OK", "Cancel", 0);
    }

    public void actionPerformed(ActionEvent ae) {
        Command c = ae.getCommand();
        Form s = Display.getInstance().getCurrent();
        if (c == NEXT_CMD || c == FINISH_CMD) {
            if(s == fUser){
                String strUser = tUser.getText();
                if( strUser != null && strUser.length() > 0 ){
                    // Save the user name and password.
                    pref.put(Preferences.kUser, strUser);
                    pref.put(Preferences.kPath, tPath.getText());
                    pref.save();
                    if (c == FINISH_CMD) {
                        showPreferencesEditor(false);
                    } else {
                        editProfile();
                    }
                }else{
                    sInfoEditUser.setText("Oops, seems that you forgot to enter a user ID...");
                }
            }else if(s == fProfile){
                String vAutoPause = cbAutoPause.isSelected() ? Preferences.vYes : Preferences.vNo;
                pref.put(Preferences.kAutoPause, vAutoPause);
                pref.put(Preferences.kProfile, String.valueOf(lsProfile.getSelectedIndex()) );
                pref.save();
                if (c == FINISH_CMD) {
                    showPreferencesEditor(false);
                } else {
                    editWsConnector();
                }
            }else if(s == fWsConnector){
                int selectedIndex = lsWsConnector.getSelectedIndex();
                RadioButton rb = lsWsConnector.getRadioButton(selectedIndex);
                String wsconn = rb.getText();
                pref.put(Preferences.kWsConnector, wsconn);
                pref.save();

                if (c == FINISH_CMD) {
                    showPreferencesEditor(false);
                } else {
                    // if user choose HTTP connection, go to edit sending interval
                    if ( wsconn.equals(Preferences.vHTTP) ) {
                        editSendInterval();
                    }else{
                        midlet.discoverDeviceTypes();
                    }
                }
            }else if(s == fSendInterval){
                String strUrl = tUrl.getText();
                if ( strUrl != null && strUrl.length() > 0 ) {
                    pref.put(Preferences.kUrl, strUrl);

                    int selectedIndex = lsSendInterval.getSelectedIndex();
                    RadioButton rb = lsSendInterval.getRadioButton(selectedIndex);
                    pref.put(Preferences.kSendInterval, rb.getText());
                    pref.save();
                    if (c == FINISH_CMD) {
                        showPreferencesEditor(false);
                    } else {
                        midlet.discoverDeviceTypes();
                    }
                } else {
                    sInfoConnection.setText("Oops, seems that you forgot to enter a URL...");
                }
            }
        }
        else if(c == START_ROUND_CMD){
            new Thread(){
                public void run(){
                    midlet.startRound();
                }
            }.start();
            midlet.getGui().showStartedConsole();
            midlet.getGui().set(Gui.K_STATUS, "Running");
        }
        else if(c == CONFIG_CMD){
            midlet.setPreferences(true);
        }
        else if(c == BT_DISCOVER_CMD){
            midlet.setDeviceType( PinkrMIDlet.BT_DEVICE_TYPE );
        }
        else if(c == SELECT_CMD ){
            if ( s.getTitle().equals(DeviceTypesMenuTitle) ) {
                String menuItem = (String) lsDeviceTypes.getSelectedItem();
                if( menuItem.equals(InternalDeviceMenuItem) ){
                    pref.put(Preferences.kDeviceType, Preferences.vBuiltin);
                    pref.put(Preferences.kConfigured, Preferences.vYes);
                    pref.save();
                    midlet.setDeviceType( PinkrMIDlet.INTERNAL_DEVICE_TYPE );
                }
                else if( menuItem.equals(BtDeviceMenuItem) ){
                    sInfoScanning.setText("Scanning for GPS device...");
                    pref.put(Preferences.kDeviceType, Preferences.vBluetooth);
                    pref.save();
                    new Thread(){
                        public void run(){
                            midlet.setDeviceType( PinkrMIDlet.BT_DEVICE_TYPE );
                        }
                    }.start();
//                    showAlert("Scanning for GPS device...");
                }
            }
            if ( s.getTitle().equals(DevicesMenuTitle) ) {
                int selectedIndex = lsBtDevices.getSelectedIndex();
                midlet.setBtRemoteDevice(selectedIndex);
                pref.put(Preferences.kBtConnectionURL, midlet.getBtConnectionURL());
                pref.put(Preferences.kConfigured, Preferences.vYes);
                pref.save();
            }
        }
        else if (c == EXIT_CMD) {
            try{
                // terminate
                midlet.terminate();
                // exit midlet
                midlet.destroyApp(true);
                midlet.notifyDestroyed();
            }catch(MIDletStateChangeException e){
                e.printStackTrace();
            }
        }
    }
}
